package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.http.HttpClient;
import java.util.Map;

/**
 * 短信发送器
 *
 * @author 凡行
 */
public class SpringHttpExecutor {
    private final Logger log = LoggerFactory.getLogger(SpringHttpExecutor.class);
    private final HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NEVER).build();

    private final RestTemplate restTemplate;
    private final String endpoint;

    public SpringHttpExecutor(RestTemplate restTemplate, String endpoint) {
        this.endpoint = endpoint;
        this.restTemplate = restTemplate;
    }

    public <T> T get(String path, Map<String, String> pathVars, Map<String, String> query, Class<T> clazz) {
        return this.execute(HttpMethod.GET, path, pathVars, query, null, clazz);
    }

    public <T> T post(String path, Map<String, String> pathVars, Map<String, String> query, Object body, Class<T> clazz) {
        return this.execute(HttpMethod.POST, path, pathVars, query, body, clazz);
    }

    public <T> T delete(String path, Map<String, String> pathVars, Map<String, String> query, Object body, Class<T> clazz) {
        return this.execute(HttpMethod.DELETE, path, pathVars, query, body, clazz);
    }

    public <T> T put(String path, Map<String, String> pathVars, Map<String, String> query, Object body, Class<T> clazz) {
        return this.execute(HttpMethod.PUT, path, pathVars, query, body, clazz);
    }

    private <T> T execute(HttpMethod httpMethod, String path, Map<String, String> pathVars, Map<String, String> query, Object body, Class<T> clazz) {
        // url
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(endpoint).path(path);
        query.forEach(builder::queryParam);
        if (CollectionUtils.isEmpty(pathVars)) {
            path = builder.toUriString();
        } else {
            path = builder.buildAndExpand(pathVars).toUriString();
        }
        // http-entity
        HttpEntity<?> entity = new HttpEntity<>(body);
        ResponseEntity<T> responseEntity = restTemplate.exchange(endpoint + builder.toUriString(), httpMethod, entity, clazz);
        log.info("execute [{}] query:{}, body={}", path, query, body);
        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            return responseEntity.getBody();
        }
        throw new RuntimeException(responseEntity.getStatusCode().toString());
    }
}
